#include "smart_mpp_decoder.hpp"

int SmartMppDecoder::init(MppCodingType type)
{
    int ret;
    MppDecCfg cfg = NULL;

    deinit();
    m_loop_run = true;

    m_dec_ctx.type = type;
    m_dec_ctx.need_split = 0;

    ret = mpp_packet_init(&m_dec_ctx.packet, NULL, 0);
    if (ret) {
        log_error("mpp_packet_init failed\n");
        deinit();
        exit(EXIT_FAILURE);
    }

    log_debug("mpp_packet_init, ret:%d.", ret);

    ret = mpp_create(&m_dec_ctx.ctx, &m_dec_ctx.mpi);
    if (ret) {
        log_debug("mpp_create failed\n");
        deinit();
        exit(EXIT_FAILURE);
    }

    log_debug("%p mpi_dec_test decoder test start w %d h %d type %d\n",
            m_dec_ctx.ctx, m_dec_ctx.width, m_dec_ctx.height, m_dec_ctx.type);

    ret = mpp_init(m_dec_ctx.ctx, MPP_CTX_DEC, type);
    if (ret) {
        log_debug("mpp_init failed\n");
        deinit();
        exit(EXIT_FAILURE);
    }

    // NOTE: timeout value please refer to MppPollType definition
    //  0   - non-block call (default)
    // -1   - block call
    // +val - timeout value in ms
    {
        // MppPollType timeout = (MppPollType)3000;
        // MppParam param = &timeout;

        // ret = m_dec_ctx.mpi->control(m_dec_ctx.ctx, MPP_SET_OUTPUT_TIMEOUT, param);
        // if (ret) {
        //     log_debug("Failed to set output timeout %d ret %d\n", timeout, ret);
        //     deinit();
        //     exit(EXIT_FAILURE);
        // }

        // ret = m_dec_ctx.mpi->control(m_dec_ctx.ctx, MPP_SET_INPUT_TIMEOUT, param);
        // if (ret) {
        //     log_debug("Failed to set input timeout %d ret %d\n", timeout, ret);
        //     deinit();
        //     exit(EXIT_FAILURE);
        // }
    }

#if 0
    /* get default config from decoder context */
    ret = m_dec_ctx.mpi->control(m_dec_ctx.ctx, MPP_DEC_GET_CFG, cfg);
    if (ret) {
        log_debug("%p failed to get decoder cfg ret %d\n", m_dec_ctx.ctx, ret);
        exit(EXIT_FAILURE);
    }

    log_debug("MPP_DEC_GET_CFG, ret:%d, cfg:%p.", ret, cfg);

    /*
     * split_parse is to enable mpp internal frame spliter when the input
     * packet is not aplited into frames.
     */
    ret = mpp_dec_cfg_set_u32(cfg, "base:split_parse", m_dec_ctx.need_split);
    if (ret) {
        log_debug("%p failed to set split_parse ret %d\n", m_dec_ctx.ctx, ret);
        exit(EXIT_FAILURE);
    }

    ret = m_dec_ctx.mpi->control(m_dec_ctx.ctx, MPP_DEC_SET_CFG, cfg);
    if (ret) {
        log_debug("%p failed to set cfg %p ret %d\n", m_dec_ctx.ctx, cfg, ret);
        exit(EXIT_FAILURE);
    }

    log_debug("MPP_DEC_SET_CFG, ret:%d.", ret);
#else
    ret = m_dec_ctx.mpi->control(m_dec_ctx.ctx, MPP_DEC_SET_PARSER_SPLIT_MODE, &m_dec_ctx.need_split);
    if (ret) {
        log_debug("%p failed to set split_parse ret %d\n", m_dec_ctx.ctx, ret);
        exit(EXIT_FAILURE);
    }
#endif

    log_debug("SmartMppDecode init ok.");
    return 0;
}

int SmartMppDecoder::deinit()
{
    m_loop_run = false;

    if (m_dec_ctx.ctx != nullptr && m_dec_ctx.mpi != nullptr) {
        m_dec_ctx.mpi->reset(m_dec_ctx.ctx);
    }

    if (m_dec_ctx.packet) {
        mpp_packet_deinit(&m_dec_ctx.packet);
        m_dec_ctx.packet = NULL;
    }

    if (m_dec_ctx.frame) {
        mpp_frame_deinit(&m_dec_ctx.frame);
        m_dec_ctx.frame = NULL;
    }

    if (m_dec_ctx.ctx) {
        mpp_destroy(m_dec_ctx.ctx);
        m_dec_ctx.ctx = NULL;
    }

    // data.frm_grp = NULL;
    // if (data.buf_mgr) {
    //     dec_buf_mgr_deinit(data.buf_mgr);
    //     data.buf_mgr = NULL;
    // }
    return 0;
}

int SmartMppDecoder::sync_decoding(uint8_t* pkt_buf, uint32_t pkt_len, std::function<void(uint8_t* frm_buf, uint32_t frm_len)> callback)
{
    MPP_RET ret;
    if (pkt_len == 0) return 0;

    // 将数据写入Packet包中
    mpp_packet_set_data(m_dec_ctx.packet, pkt_buf);
    mpp_packet_set_size(m_dec_ctx.packet, pkt_len);
    mpp_packet_set_pos(m_dec_ctx.packet, pkt_buf);
    mpp_packet_set_length(m_dec_ctx.packet, pkt_len);

    RK_S32 times;
    RK_S32 put_wait_count = 0;
    RK_S32 get_wait_count = 0;

    times = 15;
    while (m_loop_run == true) {
        ret = m_dec_ctx.mpi->decode_put_packet(m_dec_ctx.ctx, m_dec_ctx.packet);
        if (MPP_OK == ret) {
            log_debug("pkt send success, pkt len: %d.", mpp_packet_get_length(m_dec_ctx.packet));
            break;
        } else {
            ++put_wait_count;
            if(--times > 0) {
                usleep(2000);
                continue;
            }
            log_error("decode_put_packet failed too much time.");
            break;
        }
    }

    times = 15;
    RK_S32 get_frm = 0;
    while (m_loop_run == true) {
        MppFrame frame = NULL;

        ret = m_dec_ctx.mpi->decode_get_frame(m_dec_ctx.ctx, &frame);  // ret: 0为正常，表示码流己被MPP处理；非零为出现错误，码流未被处理，需要把码流重新输入
        if (MPP_ERR_TIMEOUT == ret) {
            if (times > 0) {
                times--;
                ++get_wait_count;
                usleep(2000);
                continue;
            }
            log_error("%p decode_get_frame failed too much time.", m_dec_ctx.ctx);
        }

        // ret: 0为正常，表示获取输出过程正常，需要判断是否有得到有值的frame指针；非零为出现错误
        if (ret) {
            log_debug("%p decode_get_frame failed, ret %d.", ret, m_dec_ctx.ctx);
            return 0; // mpp 内没有帧了
        }

        if (frame) {
            if (mpp_frame_get_info_change(frame)) {
                RK_U32 width = mpp_frame_get_width(frame);
                RK_U32 height = mpp_frame_get_height(frame);
                RK_U32 hor_stride = mpp_frame_get_hor_stride(frame);
                RK_U32 ver_stride = mpp_frame_get_ver_stride(frame);
                RK_U32 buf_size = mpp_frame_get_buf_size(frame);

                log_debug("%p decode_get_frame get info changed found\n", m_dec_ctx.ctx);
                log_debug("%p decoder require buffer w:h [%d:%d] stride [%d:%d] buf_size %d",
                            m_dec_ctx.ctx, width, height, hor_stride, ver_stride, buf_size);

                if (NULL == m_dec_ctx.frm_grp) {
                    /* If buffer group is not set create one and limit it */
                    ret = mpp_buffer_group_get_internal(&m_dec_ctx.frm_grp, MPP_BUFFER_TYPE_ION);
                    if (ret) {
                        log_error("%p get mpp buffer group failed ret %d\n", m_dec_ctx.ctx, ret);
                        break;
                    }

                    /* Set buffer to mpp decoder */
                    ret = m_dec_ctx.mpi->control(m_dec_ctx.ctx, MPP_DEC_SET_EXT_BUF_GROUP, m_dec_ctx.frm_grp);
                    if (ret) {
                        log_error("%p set buffer group failed ret %d\n", m_dec_ctx.ctx, ret);
                        break;
                    }
                } else {
                    /* If old buffer group exist clear it */
                    ret = mpp_buffer_group_clear(m_dec_ctx.frm_grp);
                    if (ret) {
                        log_error("%p clear buffer group failed ret %d\n", m_dec_ctx.ctx, ret);
                        break;
                    }
                }

                /* Use limit config to limit buffer count to 24 with buf_size */
                ret = mpp_buffer_group_limit_config(m_dec_ctx.frm_grp, buf_size, 24);
                if (ret) {
                    log_error("%p limit buffer group failed ret %d\n", m_dec_ctx.ctx, ret);
                    break;
                }

                /*
                    * All buffer group config done. Set info change ready to let
                    * decoder continue decoding
                    */
                ret = m_dec_ctx.mpi->control(m_dec_ctx.ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
                if (ret) {
                    log_error("%p info change ready failed ret %d\n", m_dec_ctx.ctx, ret);
                    break;
                }
            } else {
                char log_buf[256];
                RK_S32 log_size = sizeof(log_buf) - 1;
                RK_S32 log_len = 0;
                RK_U32 err_info = mpp_frame_get_errinfo(frame);
                RK_U32 discard = mpp_frame_get_discard(frame);

                log_len += snprintf(log_buf + log_len, log_size - log_len,
                                    "decode get frame %d", m_dec_ctx.frame_count);

                if (mpp_frame_has_meta(frame)) {
                    MppMeta meta = mpp_frame_get_meta(frame);
                    RK_S32 temporal_id = 0;

                    mpp_meta_get_s32(meta, KEY_TEMPORAL_ID, &temporal_id);

                    log_len += snprintf(log_buf + log_len, log_size - log_len,
                                        " tid %d", temporal_id);
                }

                if (err_info || discard) {
                    log_len += snprintf(log_buf + log_len, log_size - log_len,
                                        " err %x discard %x", err_info, discard);
                }
                log_debug("%p %s\n", m_dec_ctx.ctx, log_buf);

                m_dec_ctx.frame_count++;

                // 对解出的帧进行处理
                if ((nullptr != callback) && !err_info) {
                    /* 3. 数据回调（默认NV12） */
                    MppBuffer mpp_buffer = NULL;
                    uint8_t* base = NULL;
                    
                    m_dec_ctx.width = mpp_frame_get_width(frame);
                    m_dec_ctx.height = mpp_frame_get_height(frame);
                    m_dec_ctx.hor_stride = mpp_frame_get_hor_stride(frame);
                    m_dec_ctx.ver_stride = mpp_frame_get_ver_stride(frame);
                    m_dec_ctx.fmt = mpp_frame_get_fmt(frame);
                    mpp_buffer = mpp_frame_get_buffer(frame);
                    log_debug("w/h:%d/%d h/v:%d/%d fmt:%d buf:%p.", 
                            m_dec_ctx.width, m_dec_ctx.height,
                            m_dec_ctx.hor_stride, m_dec_ctx.ver_stride,
                            m_dec_ctx.fmt, mpp_buffer);
                    if (NULL == mpp_buffer) {
                        log_error("mpp_frame_get_buffer get mpp_buffer NULL.");
                        log_debug("error_num %d.", ++m_dec_ctx.error_num);
                    } else {
                        base = (RK_U8 *)mpp_buffer_get_ptr(mpp_buffer);
                        callback(base, m_dec_ctx.width * m_dec_ctx.height * 3 / 2);
                    }
                }

            }
            
            mpp_frame_deinit(&frame);
            get_frm = 1;
        }

        if (get_frm == 0) {
            if(--times > 0) {
                ++get_wait_count;
                usleep(2000);
                continue;
            }
            log_error("decode_get_frame failed too much time.");
            break;
        } else {
            return 0;
        }
        
        break;
    }
    log_error("decode failed, put_wait_count:%d, get_wait_count:%d.", put_wait_count, get_wait_count);
    return -2;
}

int SmartMppDecoder::put_packet(uint8_t *buf, uint32_t len)
{
    int ret;

    mpp_packet_set_data(m_dec_ctx.packet, buf);
    mpp_packet_set_size(m_dec_ctx.packet, len);
    mpp_packet_set_pos(m_dec_ctx.packet, buf);
    mpp_packet_set_length(m_dec_ctx.packet, len);

    m_dec_ctx.error_try_num = 0;
    do {
        ret = m_dec_ctx.mpi->decode_put_packet(m_dec_ctx.ctx, m_dec_ctx.packet);
        if (MPP_OK != ret) {  // if failed wait a moment and retry
            usleep(2000);
            log_debug("decode_put_packet timeout.");
        }
    } while ((ret != MPP_OK) && (++m_dec_ctx.error_try_num <= MAX_DEC_ERROR_TRY_NUM));

    return 0;
}

int SmartMppDecoder::loop_get_frame(std::function<void(std::vector<uint8_t>&)> callback)
{
    int ret;
    uint32_t frm_eos;
    std::vector<uint8_t> data;

    m_loop_run = true;
    while (true == m_loop_run) {
        /* 1. 获取一帧Frame，阻塞方式获取 */ 
        ret = m_dec_ctx.mpi->decode_get_frame(m_dec_ctx.ctx, &m_dec_ctx.frame);

        if (MPP_ERR_TIMEOUT == ret) {  // 超时
            // log_debug("decode_get_frame failed too much time.");
            continue;
        }

        if (ret) {
            log_error("decode_get_frame failed ret %d\n", ret);
            continue;
        }

        /* 2. 处理Frame */
        if (NULL != m_dec_ctx.frame) {
            if (mpp_frame_get_info_change(m_dec_ctx.frame)) {
                // found info change and create buffer group for decoding
                m_dec_ctx.width = mpp_frame_get_width(m_dec_ctx.frame);
                m_dec_ctx.height = mpp_frame_get_height(m_dec_ctx.frame);
                m_dec_ctx.hor_stride = mpp_frame_get_hor_stride(m_dec_ctx.frame);
                m_dec_ctx.ver_stride = mpp_frame_get_ver_stride(m_dec_ctx.frame);
                m_dec_ctx.frame_buf_size = mpp_frame_get_buf_size(m_dec_ctx.frame);

                data.reserve(m_dec_ctx.width * m_dec_ctx.height * 3 / 2);  // NV12

                log_debug("decode_get_frame get info changed found.");
                log_debug("decoder require buffer w:h [%d:%d] stride [%d:%d] size %d.",
                            m_dec_ctx.width, m_dec_ctx.height, 
                            m_dec_ctx.hor_stride, m_dec_ctx.ver_stride, m_dec_ctx.frame_buf_size);

                if (NULL == m_dec_ctx.frm_grp) {
                    /* If buffer group is not set create one and limit it */
                    ret = mpp_buffer_group_get_internal(&m_dec_ctx.frm_grp, MPP_BUFFER_TYPE_ION);
                    if (ret) {
                        log_error("get mpp buffer group failed ret %d\n", ret);
                        return ret;
                    }

                    /* Set buffer to mpp decoder */
                    ret = m_dec_ctx.mpi->control(m_dec_ctx.ctx, MPP_DEC_SET_EXT_BUF_GROUP, m_dec_ctx.frm_grp);
                    if (ret) {
                        log_error("set buffer group failed ret %d\n", ret);
                        return ret;
                    }
                } else {
                    /* If old buffer group exist clear it */
                    ret = mpp_buffer_group_clear(m_dec_ctx.frm_grp);
                    if (ret) {
                        log_error("clear buffer group failed ret %d\n", ret);
                        return ret;
                    }
                }

                /* Use limit config to limit buffer count to 24 with buf_size */
                ret = mpp_buffer_group_limit_config(m_dec_ctx.frm_grp, m_dec_ctx.frame_buf_size, 24);
                if (ret) {
                    log_error("limit buffer group failed ret %d\n", ret);
                    return ret;
                }

                //  开启继续解码
                ret = m_dec_ctx.mpi->control(m_dec_ctx.ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
                if (ret) {
                    log_error("info change ready failed ret %d\n", ret);
                    return ret;
                }
            } else {
                uint32_t err_info = 0;

                err_info = mpp_frame_get_errinfo(m_dec_ctx.frame) | mpp_frame_get_discard(m_dec_ctx.frame);
                if (err_info) {
                    log_debug("decoder_get_frame get err info:%d discard:%d.\n",
                                mpp_frame_get_errinfo(m_dec_ctx.frame),
                                mpp_frame_get_discard(m_dec_ctx.frame));
                    log_debug("decoder_get_frame get error_num %d.", ++m_dec_ctx.error_num);
                }
                log_debug("decode_get_frame get frame %d\n", m_dec_ctx.frame_count++);

                if ((nullptr != callback) && !err_info) {
                    /* 3. 数据回调（默认NV12） */
                    data.clear();
                    MppBuffer mpp_buffer = NULL;
                    uint8_t* base = NULL;
                    uint8_t* base_y = NULL;
                    uint8_t* base_c = NULL;

                    m_dec_ctx.width = mpp_frame_get_width(m_dec_ctx.frame);
                    m_dec_ctx.height = mpp_frame_get_height(m_dec_ctx.frame);
                    m_dec_ctx.hor_stride = mpp_frame_get_hor_stride(m_dec_ctx.frame);
                    m_dec_ctx.ver_stride = mpp_frame_get_ver_stride(m_dec_ctx.frame);
                    m_dec_ctx.fmt = mpp_frame_get_fmt(m_dec_ctx.frame);
                    mpp_buffer = mpp_frame_get_buffer(m_dec_ctx.frame);

                    if (NULL == mpp_buffer) {
                        log_error("mpp_frame_get_buffer get mpp_buffer NULL.");
                        log_debug("error_num %d.", ++m_dec_ctx.error_num);
                    } else {
                        base = (RK_U8 *)mpp_buffer_get_ptr(mpp_buffer);
                        base_y = base;
                        base_c = base + m_dec_ctx.hor_stride * m_dec_ctx.ver_stride;
#if 1
                        auto begin_time = std::chrono::high_resolution_clock::now();
                        for (int i = 0; i < m_dec_ctx.height; ++i) {
                            data.insert(data.end(), base_y, base_y+m_dec_ctx.width);
                            base_y += m_dec_ctx.hor_stride;
                        }
                        for (int i = 0; i < m_dec_ctx.height/2; ++i) {
                            data.insert(data.end(), base_c, base_c+m_dec_ctx.width);
                            base_c += m_dec_ctx.hor_stride;
                        }
                        // auto end_time = std::chrono::high_resolution_clock::now();
                        // std::chrono::microseconds time_Interval = std::chrono::duration_cast<std::chrono::microseconds>(end_time - begin_time).count();
                        // log_debug("> vector insert time:%d ms, insert len:%d.", timeInterval.count(), data.size());
#else
                        for (int i = 0; i < m_dec_ctx.height; ++i, base_y += m_dec_ctx.hor_stride) {
                            data.insert(data.end(), base_y, base_y+m_dec_ctx.width);
                        }
                        for (int i = 0; i < m_dec_ctx.height/2; ++i, base_c += m_dec_ctx.hor_stride) {
                            data.insert(data.end(), base_c, base_c+m_dec_ctx.width);
                        }
#endif
                        callback(data);
                    }
                }
            }

            frm_eos = mpp_frame_get_eos(m_dec_ctx.frame);
            mpp_frame_deinit(&m_dec_ctx.frame); 
        } else {
            log_error("decode_get_frame get frame NULL, ret %d", ret);
            log_debug("error_num %d.", ++m_dec_ctx.error_num);
        }

        /* 4. 异常控制 */        
        if (frm_eos) {
            init(m_dec_ctx.type);
        }

        if (m_dec_ctx.error_num >= MAX_DEC_ERROR_NUM) {
            init(m_dec_ctx.type);
        }
    }

    return 0;
}

int SmartMppDecoder::loop_get_frame_raw(std::function<void(uint8_t*, uint32_t)> callback)
{
    int ret;
    uint32_t frm_eos;

    m_loop_run = true;
    while (true == m_loop_run) {
        /* 1. 获取一帧Frame，阻塞方式获取 */ 
        ret = m_dec_ctx.mpi->decode_get_frame(m_dec_ctx.ctx, &m_dec_ctx.frame);

        if (MPP_ERR_TIMEOUT == ret) {  // 超时
            // log_debug("decode_get_frame failed too much time.");
            continue;
        }

        if (ret) {
            log_error("decode_get_frame failed ret %d\n", ret);
            continue;
        }

        /* 2. 处理Frame */
        if (NULL != m_dec_ctx.frame) {
            if (mpp_frame_get_info_change(m_dec_ctx.frame)) {
                // found info change and create buffer group for decoding
                m_dec_ctx.width = mpp_frame_get_width(m_dec_ctx.frame);
                m_dec_ctx.height = mpp_frame_get_height(m_dec_ctx.frame);
                m_dec_ctx.hor_stride = mpp_frame_get_hor_stride(m_dec_ctx.frame);
                m_dec_ctx.ver_stride = mpp_frame_get_ver_stride(m_dec_ctx.frame);
                m_dec_ctx.frame_buf_size = mpp_frame_get_buf_size(m_dec_ctx.frame);

                log_debug("decode_get_frame get info changed found.");
                log_debug("decoder require buffer w:h [%d:%d] stride [%d:%d] size %d.",
                            m_dec_ctx.width, m_dec_ctx.height, 
                            m_dec_ctx.hor_stride, m_dec_ctx.ver_stride, m_dec_ctx.frame_buf_size);

                if (NULL == m_dec_ctx.frm_grp) {
                    /* If buffer group is not set create one and limit it */
                    ret = mpp_buffer_group_get_internal(&m_dec_ctx.frm_grp, MPP_BUFFER_TYPE_ION);
                    if (ret) {
                        log_error("get mpp buffer group failed ret %d\n", ret);
                        return ret;
                    }

                    /* Set buffer to mpp decoder */
                    ret = m_dec_ctx.mpi->control(m_dec_ctx.ctx, MPP_DEC_SET_EXT_BUF_GROUP, m_dec_ctx.frm_grp);
                    if (ret) {
                        log_error("set buffer group failed ret %d\n", ret);
                        return ret;
                    }
                } else {
                    /* If old buffer group exist clear it */
                    ret = mpp_buffer_group_clear(m_dec_ctx.frm_grp);
                    if (ret) {
                        log_error("clear buffer group failed ret %d\n", ret);
                        return ret;
                    }
                }

                /* Use limit config to limit buffer count to 24 with buf_size */
                ret = mpp_buffer_group_limit_config(m_dec_ctx.frm_grp, m_dec_ctx.frame_buf_size, 24);
                if (ret) {
                    log_error("limit buffer group failed ret %d\n", ret);
                    return ret;
                }

                //  开启继续解码
                ret = m_dec_ctx.mpi->control(m_dec_ctx.ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
                if (ret) {
                    log_error("info change ready failed ret %d\n", ret);
                    return ret;
                }
            } else {
                uint32_t err_info = 0;

                err_info = mpp_frame_get_errinfo(m_dec_ctx.frame) | mpp_frame_get_discard(m_dec_ctx.frame);
                if (err_info) {
                    log_debug("decoder_get_frame get err info:%d discard:%d.\n",
                                mpp_frame_get_errinfo(m_dec_ctx.frame),
                                mpp_frame_get_discard(m_dec_ctx.frame));
                    log_debug("decoder_get_frame get error_num %d.", ++m_dec_ctx.error_num);
                }
                log_debug("decode_get_frame get frame %d\n", m_dec_ctx.frame_count++);

                if ((nullptr != callback) && !err_info) {
                    /* 3. 数据回调（默认NV12） */
                    MppBuffer mpp_buffer = NULL;
                    uint8_t* buf = NULL;
                    uint32_t len;

                    m_dec_ctx.fmt = mpp_frame_get_fmt(m_dec_ctx.frame);
                    mpp_buffer = mpp_frame_get_buffer(m_dec_ctx.frame);

                    log_debug("mpp_frame_get_fmt %d.", m_dec_ctx.fmt);
                    if (NULL == mpp_buffer) {
                        log_error("mpp_frame_get_buffer get mpp_buffer NULL.");
                        log_debug("error_num %d.", ++m_dec_ctx.error_num);
                    } else {
                        buf = (uint8_t*)mpp_buffer_get_ptr(mpp_buffer);
                        len = mpp_buffer_get_size(mpp_buffer);
                        callback(buf, len);
                    }
                }
            }

            frm_eos = mpp_frame_get_eos(m_dec_ctx.frame);
            mpp_frame_deinit(&m_dec_ctx.frame); 
        } else {
            log_error("decode_get_frame get frame NULL, ret %d", ret);
            log_debug("error_num %d.", ++m_dec_ctx.error_num);
        }

        /* 4. 异常控制 */        
        if (frm_eos) {
            init(m_dec_ctx.type);
        }

        if (m_dec_ctx.error_num >= MAX_DEC_ERROR_NUM) {
            init(m_dec_ctx.type);
        }
    }

    return 0;
}

int SmartMppDecoder::loop_get_frame(std::function<void(uint8_t*, uint32_t)> callback)
{
    int ret;
    uint32_t frm_eos;
    uint8_t* data = NULL;
    uint32_t data_max;
    uint32_t data_len;

    m_loop_run = true;
    while (true == m_loop_run) {
        /* 1. 获取一帧Frame，阻塞方式获取 */ 
        ret = m_dec_ctx.mpi->decode_get_frame(m_dec_ctx.ctx, &m_dec_ctx.frame);

        if (MPP_ERR_TIMEOUT == ret) {  // 超时
            // log_debug("decode_get_frame failed too much time.");
            continue;
        }

        if (ret) {
            log_error("decode_get_frame failed ret %d\n", ret);
            continue;
        }

        /* 2. 处理Frame */
        if (NULL != m_dec_ctx.frame) {
            if (mpp_frame_get_info_change(m_dec_ctx.frame)) {
                // found info change and create buffer group for decoding
                m_dec_ctx.width = mpp_frame_get_width(m_dec_ctx.frame);
                m_dec_ctx.height = mpp_frame_get_height(m_dec_ctx.frame);
                m_dec_ctx.hor_stride = mpp_frame_get_hor_stride(m_dec_ctx.frame);
                m_dec_ctx.ver_stride = mpp_frame_get_ver_stride(m_dec_ctx.frame);
                m_dec_ctx.frame_buf_size = mpp_frame_get_buf_size(m_dec_ctx.frame);

                log_debug("decode_get_frame get info changed found.");
                log_debug("decoder require buffer w:h [%d:%d] stride [%d:%d] size %d.",
                            m_dec_ctx.width, m_dec_ctx.height, 
                            m_dec_ctx.hor_stride, m_dec_ctx.ver_stride, m_dec_ctx.frame_buf_size);

                if (NULL == m_dec_ctx.frm_grp) {
                    /* If buffer group is not set create one and limit it */
                    ret = mpp_buffer_group_get_internal(&m_dec_ctx.frm_grp, MPP_BUFFER_TYPE_ION);
                    if (ret) {
                        log_error("get mpp buffer group failed ret %d\n", ret);
                        if (NULL != data) free(data); 
                        return ret;
                    }

                    /* Set buffer to mpp decoder */
                    ret = m_dec_ctx.mpi->control(m_dec_ctx.ctx, MPP_DEC_SET_EXT_BUF_GROUP, m_dec_ctx.frm_grp);
                    if (ret) {
                        log_error("set buffer group failed ret %d\n", ret);
                        if (NULL != data) free(data); 
                        return ret;
                    }
                } else {
                    /* If old buffer group exist clear it */
                    ret = mpp_buffer_group_clear(m_dec_ctx.frm_grp);
                    if (ret) {
                        log_error("clear buffer group failed ret %d\n", ret);
                        if (NULL != data) free(data); 
                        return ret;
                    }
                }

                /* Use limit config to limit buffer count to 24 with buf_size */
                ret = mpp_buffer_group_limit_config(m_dec_ctx.frm_grp, m_dec_ctx.frame_buf_size, 24);
                if (ret) {
                    log_error("limit buffer group failed ret %d\n", ret);
                    if (NULL != data) free(data); 
                    return ret;
                }

                //  开启继续解码
                ret = m_dec_ctx.mpi->control(m_dec_ctx.ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
                if (ret) {
                    log_error("info change ready failed ret %d\n", ret);
                    if (NULL != data) free(data); 
                    return ret;
                }
            } else {
                uint32_t err_info = 0;

                err_info = mpp_frame_get_errinfo(m_dec_ctx.frame) | mpp_frame_get_discard(m_dec_ctx.frame);
                if (err_info) {
                    log_debug("decoder_get_frame get err info:%d discard:%d.\n",
                                mpp_frame_get_errinfo(m_dec_ctx.frame),
                                mpp_frame_get_discard(m_dec_ctx.frame));
                    log_debug("decoder_get_frame get error_num %d.", ++m_dec_ctx.error_num);
                }
                log_debug("decode_get_frame get frame %d\n", m_dec_ctx.frame_count++);

                if ((nullptr != callback) && !err_info) {
                    /* 3. 数据回调（默认NV12） */
                    MppBuffer mpp_buffer = NULL;
                    uint8_t* base = NULL;
                    uint8_t* base_y = NULL;
                    uint8_t* base_c = NULL;
                    uint8_t* buf = NULL;
                    uint32_t len;

                    m_dec_ctx.fmt = mpp_frame_get_fmt(m_dec_ctx.frame);
                    mpp_buffer = mpp_frame_get_buffer(m_dec_ctx.frame);

                    log_debug("mpp_frame_get_fmt %d.", m_dec_ctx.fmt);
                    if (NULL == mpp_buffer) {
                        log_error("mpp_frame_get_buffer get mpp_buffer NULL.");
                        log_debug("error_num %d.", ++m_dec_ctx.error_num);
                    } else {
                        base = (RK_U8 *)mpp_buffer_get_ptr(mpp_buffer);
                        base_y = base;
                        base_c = base + m_dec_ctx.hor_stride * m_dec_ctx.ver_stride;


                        if (NULL == data) {
                            data_max = m_dec_ctx.width * m_dec_ctx.height * 3 / 2;
                            data_len = 0;
                            data = (uint8_t*)malloc(data_max);
                            if (data == NULL) {
                                log_error("malloc failed.");
                                exit(EXIT_FAILURE);
                            }
                        }

                        if (data != NULL && data_max >=  m_dec_ctx.width * m_dec_ctx.height * 3 / 2) {
                            data_len = 0;
                            std::chrono::high_resolution_clock::time_point begin_time = std::chrono::high_resolution_clock::now();
#if 0  // 42ms
                            memcpy(data, base, m_dec_ctx.height*m_dec_ctx.width);
                            memcpy(data+m_dec_ctx.height*m_dec_ctx.width, 
                                    base+m_dec_ctx.hor_stride*m_dec_ctx.ver_stride, 
                                    m_dec_ctx.height*m_dec_ctx.width/2);
#endif

#if 1  // 6ms 42ms
                            for (int i = 0; i < m_dec_ctx.height; ++i) {
                                memcpy(data+data_len, base_y, m_dec_ctx.width);
                                data_len +=  m_dec_ctx.width;
                                base_y += m_dec_ctx.hor_stride;
                            }

                            for (int i = 0; i < m_dec_ctx.height/2; ++i) {
                                memcpy(data+data_len, base_c, m_dec_ctx.width);
                                data_len +=  m_dec_ctx.width;
                                base_c += m_dec_ctx.hor_stride;
                            }
#endif
                            std::chrono::high_resolution_clock::time_point end_time = std::chrono::high_resolution_clock::now();
                            std::chrono::milliseconds timeInterval = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - begin_time);
                            log_debug("> time:%d ms.", timeInterval.count());
                            callback(data, data_len);
                        }

                        
                        
                    }
                }
            }

            frm_eos = mpp_frame_get_eos(m_dec_ctx.frame);
            mpp_frame_deinit(&m_dec_ctx.frame); 
        } else {
            log_error("decode_get_frame get frame NULL, ret %d", ret);
            log_debug("error_num %d.", ++m_dec_ctx.error_num);
        }

        /* 4. 异常控制 */        
        if (frm_eos) {
            init(m_dec_ctx.type);
        }

        if (m_dec_ctx.error_num >= MAX_DEC_ERROR_NUM) {
            init(m_dec_ctx.type);
        }
    }

    if (NULL != data) free(data); 

    return 0;
}

int SmartMppDecoder::stop()
{
    m_loop_run = false;
    return 0;
}